with Ada.Containers.Indefinite_Hashed_Maps;
with Ada.Strings.Hash;

with Percentages;
with Website_Retrieval.HTTP_Get;
with App_Configuration; use App_Configuration;

--
--    queue multiple Websites Retrieval HTTP Get Retrieve requests
--    run each in turn, using another thread
--
--    similar to active object pattern as is transparent to client: using
--    additional thread(s)
--
--    dissimilar as is not exactly an object / an Ada type, but a package
--    and a procedure(s)
--

generic

   --
   -- maximum size of website to download
   --

   Max_Download_WGetter : Positive := HEAP_LIMIT;

   --
   -- maximum number of download requests to queue up
   --

   Max_Download_Requests : Positive := 10;


package WGetter is

   --
   -- wrap functionality of 'Retrieve' method of Website Retrieval
   --
   --    only download to file is provided / wrapped
   --

--     package WebGet_Type is new Website_Retrieval(
--
--           Max_Download => Max_Download );
--
--     use WebGet_Type;

   package WebGet_Type is new Website_Retrieval( Max_Download_WGetter );

   -- access the parent class' useful constants, argument types

   use WebGet_Type;

   -- create instance of child class which implements desired functionality

   package WebGetHTTP_Type is new WebGet_Type.HTTP_Get( Max_Download_WGetter );

   use WebGetHTTP_Type;

   -- get the interface type used essentially as a mediator

   WebGet_Obj : WebGetHTTP_Type.Website_Retrieval_Object;


   --
   -- argument subtypes
   --
   --    more easily provided String rather than bounded string's as used by
   --    websites_retrieval-http_get implementing package
   --

   subtype Website_Address_Arg_Type is String

         with Dynamic_Predicate =>

            Website_Address_Arg_Type'Length <= WebGet_Type.HOST_MAX_LENGTH and

            Website_Address_Arg_Type'Length >= WebGet_Type.HOST_MIN_LENGTH;

   subtype File_Name_Arg_Type is String

         with Dynamic_Predicate =>

            File_Name_Arg_Type'Length <= WebGet_Type.FILE_NAME_MAX_LENGTH and
            File_Name_Arg_Type'Length >= 1;


   --
   -- define hash function for use of hashed map collection
   --

   function Hash( Value_In : String )
         return Ada.Containers.Hash_Type is ( Ada.Strings.Hash( Value_In ));


   --
   -- URL and file name which to use for saving
   --

   package Requests_Map_Type is new Ada.Containers.Indefinite_Hashed_Maps(

         Key_Type     => String,

         Element_Type => String,

         Hash => Hash,

         Equivalent_Keys => "=" );

   use Requests_Map_Type;


   --
   -- percentage complete for download of given URL
   --

   package Requests_Status_Map_Type is new Ada.Containers
         .Indefinite_Hashed_Maps(

         Key_Type     => String,

         Element_Type => Positive,

         Hash => Hash,

         Equivalent_Keys => "=" );

   use Requests_Status_Map_Type;


   --
   -- wrap 'Retrieve'
   --
   --    active object, queue the website download requests, processing each
   --       one in turn
   --

   procedure WGet( Website : String;

                   File_Name : String );


   --
   -- percentage complete calculation utility and types
   --

   type Percentage_Calc is delta 0.01 digits 15;

   package Percentage_Type is new Percentages( Percentage_Calc,
                                               Percentage_Calc );

   use Percentage_Type;


private

   --
   -- synchronized type for storage of website download requests and statuses
   --

   protected type Requests_Queue_Type
   is

      --
      -- request download URL, save to file
      --

      entry Add_Req( Website_URL : in String;

                     File_Name   : in String );


      --
      -- retrieve first entry: URL, file name
      --
      --    provides a synchronized iteration, FIFO access
      --

      entry Fetch_Req( Website_URL_Fetched : out String;

                       File_Name_Fetched : out String );


      --
      -- mark download URL as complete
      --

      entry Remove_Req( Website_URL : in String );


      --
      -- update download URL % complete
      --

      entry Update_Status( Website_URL : in String;

                           Percentage_Complete : in Percentage_Type_Int );


      --
      -- retrieve download URL % complete
      --

      entry Get_Status( Website_URL : in String;
                        Percentage_Complete : out Percentage_Type_Int );


      --
      -- encapsulation routines for immutable access to the private
      --

      entry Copy_Queue( Map_In : out Requests_Map_Type.Map );

      entry Copy_Statuses( Map_In : out Requests_Status_Map_Type.Map );


   private

      --
      -- queue of website download requests
      --

      Queue : Requests_Map_Type.Map;

      --
      -- percentage of download complete
      --

      Statuses : Requests_Status_Map_Type.Map;


   end Requests_Queue_Type;


   --
   -- single instance of the synchronized URL download requests queue
   --    referred to by multiple threads
   --

   Requests_Queue : Requests_Queue_Type;


   --
   -- starts/restarts download processing for queued requests
   --
   --    active object processing loop
   --

   task type Active_Object_Processing is

      entry Start;

      entry Fetch_Req( Website_URL_Fetched : out String;

                       File_Name_Fetched   : out String );

   end Active_Object_Processing;


end WGetter;